import folium
from folium.plugins import AntPath, FloatImage
from pyproj import Transformer
import numpy as np
from shapely.geometry import LineString, Point
import requests

# 百度坐标系转换类（BD09 -> WGS84）
class CoordinateConverter:
    def __init__(self):
        self.transformer = Transformer.from_crs(
            {"proj": 'tmerc', "lat_0": 0, "lon_0": 117, "k": 0.9996, 
             "x_0": 500000, "y_0": 0, "ellps": "GRS80", "units": "m"},
            "EPSG:4326"
        )

    def bd09_to_wgs84(self, lng, lat):
        # 百度坐标系转换（需先转GCJ02再转WGS84）
        x, y = lng, lat
        z = np.sqrt(x**2 + y**2) + 0.00002 * np.sin(y * np.pi)
        theta = np.arctan2(y, x) + 0.000003 * np.cos(x * np.pi)
        gcj_lng = z * np.cos(theta) + 0.0065
        gcj_lat = z * np.sin(theta) + 0.006
        return self.transformer.transform(gcj_lat, gcj_lng)

# 路径优化类
class PathOptimizer:
    @staticmethod
    def douglas_peucker(points, epsilon=0.0001):
        """道格拉斯-普克算法优化路径"""
        dmax = 0
        index = 0
        end = len(points) - 1
        for i in range(1, end):
            d = PathOptimizer._perpendicular_distance(points[i], points[0], points[end])
            if d > dmax:
                index = i
                dmax = d
        if dmax > epsilon:
            res1 = PathOptimizer.douglas_peucker(points[:index+1], epsilon)
            res2 = PathOptimizer.douglas_peucker(points[index:], epsilon)
            return res1[:-1] + res2
        else:
            return [points[0], points[end]]

    @staticmethod
    def _perpendicular_distance(point, line_start, line_end):
        """计算点到线段的垂直距离"""
        x, y = point
        x1, y1 = line_start
        x2, y2 = line_end
        A = x - x1
        B = y - y1
        C = x2 - x1
        D = y2 - y1
        dot = A * C + B * D
        len_sq = C * C + D * D
        param = -1 if len_sq == 0 else dot / len_sq
        xx = x1 + param * C
        yy = y1 + param * D
        dx = x - xx
        dy = y - yy
        return np.sqrt(dx * dx + dy * dy)

# 主程序
if __name__ == "__main__":
    # 示例百度路径坐标（需替换为实际数据）
    raw_bd09_coords = [
        [116.4074, 39.9042], [116.4085, 39.9038], [116.4092, 39.9035],
        [116.4098, 39.9032], [116.4105, 39.9028]
    ]

    # 初始化转换器
    converter = CoordinateConverter()
    
    # 坐标转换
    wgs84_coords = [converter.bd09_to_wgs84(lng, lat) for lng,lat in raw_bd09_coords]
    
    # 路径优化
    optimized_coords = PathOptimizer.douglas_peucker(wgs84_coords)
    
    # 创建高德地图
    m = folium.Map(
        location=optimized_coords[0],
        zoom_start=17,
        tiles='https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
        attr='高德地图'
    )

    # 绘制道路网络（示例）
    road_layer = folium.GeoJson(
        'beijing_roads.geojson',  # 需替换为实际路网数据
        style_function=lambda x: {'color':'gray','weight':1}
    ).add_to(m)

    # 绘制优化路径
    folium.PolyLine(
        locations=optimized_coords,
        color='#FF5733',
        weight=5,
        opacity=0.8,
        popup="优化路径"
    ).add_to(m)

    # 添加验证点
    for point in raw_bd09_coords:
        folium.CircleMarker(
            location=converter.bd09_to_wgs84(*point),
            radius=3,
            color='#FF0000',
            fill=True,
            fill_opacity=0.7,
            popup=f"原始点: {point}"
        ).add_to(m)

    # 添加路径节点
    for idx, (lat, lng) in enumerate(optimized_coords):
        folium.Marker(
            location=[lat, lng],
            popup=f"节点 {idx+1}",
            icon=folium.Icon(
                icon='circle',
                color='#4B0082',
                fill=True,
                fill_opacity=0.7
            )
        ).add_to(m)

    # 自动调整视野
    m.fit_bounds(m.get_bounds())

    # 保存地图
    m.save("corrected_route.html")

    # 可选：调用百度API验证路径点
    def verify_road_point(lat, lng):
        url = f"http://api.map.baidu.com/geocoder?location={lat},{lng}&output=json&key=YOUR_API_KEY"
        result = requests.get(url).json()
        return result['result']['precise'] > 0.8

    # 验证并输出异常点
    for idx, (lat, lng) in enumerate(optimized_coords):
        if not verify_road_point(lat, lng):
            print(f"警告: 节点 {idx+1}({lat:.6f},{lng:.6f}) 可能偏离道路")